#include "ifftgpu.h"
#include <list>

using namespace std;

Static planner_static;

Plan * make_choice(Plan * p1, Plan * p2)
{
    planner_static.nchoice ++;

    if (!p1) goto choose_p2;
    if (!p2) goto choose_p1;

    if (p1->pass < p2->pass) 
        goto choose_p1;
    else if(p1->pass > p2->pass)
        goto choose_p2;

    if (p1->cost < p2->cost) 
        goto choose_p1;
    else if(p1->cost > p2->cost)
        goto choose_p2;

choose_p1:
    destroy_plan(p2);
    return p1;

choose_p2:
    destroy_plan(p1);
    return p2;
}

Plan * search_solvers(Solver * solvers[], Problem * prob)
{
    Plan * p = NULL;
    Plan * bestp = NULL;

    Solver ** solvpp = solvers;
    while (*solvpp) {
        Solver * solvp = *solvpp;

        p = solvp->make_plan(prob);
        while (p) {
            bestp = make_choice(bestp, p);
            p = solvp->make_next_plan(prob);
        }

        solvpp ++;
    }

    return bestp;
}

void destroy_solvers(Solver * solvers[])
{
    Solver ** solvpp = solvers;
    while (*solvpp) {
        SAFE_DELETE(*solvpp);
        solvpp ++;
    }
}

FFTGPU_EXPORT void destroy_plan(Plan * p)
{
    SAFE_DELETE(p);
}

FFTGPU_EXPORT Plan * make_plan(Problem * prob)
{
    planner_static.nprob ++;

    Plan * p = NULL;
    Solver * solverTab[] = {
        new DIRSolver,
        new CTSolver,
        NULL
    };

// print problem
    printf("Problem: %d I:", prob->fftDim[0]);
    list<Dim>::iterator i;
    for (i = prob->iDim.begin(); i != prob->iDim.end(); i++) {
        printf("(%d,%d)", i->n, i->stride);
    }
    printf(" O:");
    for (i = prob->oDim.begin(); i != prob->oDim.end(); i++) {
        printf("(%d,%d)", i->n, i->stride);
    }
    printf("\n");


    p = search_solvers(solverTab, prob);

    destroy_solvers(solverTab);
    return p;
}

FFTGPU_EXPORT Static & get_static()
{
    return planner_static;
}
